package com.example.demo.utils;

import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.file.Files;
import java.util.zip.*;

/**
 * ѹ��������
 *
 * @author Administrator
 */
public class ZipHelper {
    private static Logger logger = LoggerFactory.getLogger(ZipHelper.class);

    private static final int BUFFER_SIZE = 1024;

    private static final String PATH_SEP = "/";


    private ZipHelper() {
    }

    /**
     * @param sourceFileName
     * @param destFileName
     * @throws IOException
     */
    public static void zipCompress(String sourceFileName, String destFileName) throws IOException {
        File sourceFile = new File(sourceFileName);
        File destFile = new File(destFileName);
        zipCompress(sourceFile, destFile);
    }

    /**
     * @param sourceFile
     * @param destFile
     * @throws IOException
     */
    public static void zipCompress(File sourceFile, File destFile) throws IOException {
        try (
                FileOutputStream fos = new FileOutputStream(destFile);
                CheckedOutputStream cos = new CheckedOutputStream(fos, new CRC32());
                ZipOutputStream zos = new ZipOutputStream(cos);
        ) {
            zipCompress(sourceFile, zos, "");
            zos.flush();
            zos.finish();

            IOUtils.closeQuietly(zos);
            IOUtils.closeQuietly(cos);
            IOUtils.closeQuietly(fos);
        }
    }

    /**
     * @param sourceFile
     * @param zos
     * @param basePath
     * @throws IOException
     */
    private static void zipCompress(File sourceFile, ZipOutputStream zos, String basePath) throws IOException {
        if (sourceFile.isDirectory()) {
            zipCompressDir(sourceFile, zos, basePath);
        } else {
            zipCompressFile(sourceFile, zos, basePath);
        }
    }

    /**
     * ���ļ��н���ѹ�����������
     *
     * @param dir      �ļ���
     * @param zos      �����
     * @param basePath ѹ���ļ��е����·��
     * @throws IOException
     */
    private static void zipCompressDir(File dir, ZipOutputStream zos, String basePath) throws IOException {
        File[] files = dir.listFiles();
        String newBasePath = basePath + dir.getName() + PATH_SEP;
        //������Ŀ¼
        if (files.length <= 0) {
            ZipEntry entry = new ZipEntry(newBasePath);
            zos.putNextEntry(entry);
            zos.closeEntry();
        }
        //�ݹ�ѹ��
        for (File file : files) {
            zipCompress(file, zos, newBasePath);
        }
    }

    /**
     * ���ļ�����ѹ�����������
     *
     * @param file     ��ѹ���ļ�
     * @param zos      �����
     * @param basePath ѹ���ļ��е����·��
     * @throws IOException
     */
    private static void zipCompressFile(File file, ZipOutputStream zos, String basePath) throws IOException {
        String entryName = basePath + file.getName();
        FileInputStream fis = new FileInputStream(file);
        zipCompress(fis, zos, entryName);
    }

    public static byte[] zipCompress(InputStream is, String entryName) {

        byte[] result = null;
        try (
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                CheckedOutputStream cos = new CheckedOutputStream(baos, new CRC32());
                ZipOutputStream zos = new ZipOutputStream(cos);
        ) {
            zos.setMethod(ZipOutputStream.DEFLATED);
            zipCompress(is, zos, entryName);

            zos.flush();
            zos.finish();

            result = baos.toByteArray();

            IOUtils.closeQuietly(baos);
            IOUtils.closeQuietly(cos);
            IOUtils.closeQuietly(zos);

        } catch (Exception e) {
            logger.error(e.getMessage());
        }
        return result;
    }

    /**
     * @param is        ��ѹ������
     * @param zos       ѹ����������
     * @param entryName ԭʼ�ļ���
     * @throws IOException
     */
    private static void zipCompress(InputStream is, ZipOutputStream zos, String entryName) throws IOException {
        try (
                BufferedInputStream bis = new BufferedInputStream(is);
        ) {
            ZipEntry entry = new ZipEntry(entryName);
            zos.putNextEntry(entry);
            int count;
            byte[] buffer = new byte[BUFFER_SIZE];
            while (true) {
                count = bis.read(buffer, 0, BUFFER_SIZE);
                if (count < 0) {
                    break;
                }
                zos.write(buffer, 0, count);
            }
            zos.closeEntry();
            IOUtils.closeQuietly(bis);
        }
    }

    /**
     * ��ѹ���ļ���ѹ����Ŀ���ļ���
     *
     * @param sourceFileName
     * @param destDir
     * @throws IOException
     */
    public static void zipDecompress(String sourceFileName, String destDir) throws IOException {
        zipDecompress(new File(sourceFileName), new File(destDir));
    }

    /**
     * ��ѹ���ļ���ѹ����Ŀ���ļ���
     *
     * @param sourceFile
     * @param destDir
     * @throws IOException
     */
    public static void zipDecompress(File sourceFile, File destDir) throws IOException {
        try (
                FileInputStream fis = new FileInputStream(sourceFile);
        ) {
            zipDecompress(fis, destDir);
            IOUtils.closeQuietly(fis);
        }
    }

    /**
     * ������е����ݽ�ѹ����Ŀ���ļ���
     *
     * @param sourceBytes
     * @param destDir
     * @throws IOException
     */
    public static void zipDecompress(byte[] sourceBytes, File destDir) throws IOException {
        try (
                ByteArrayInputStream bais = new ByteArrayInputStream(sourceBytes);
        ) {

            zipDecompress(bais, destDir);
            IOUtils.closeQuietly(bais);
        }
    }

    /**
     * �����е����ݽ�ѹ����Ŀ���ļ���
     *
     * @param is
     * @param destFile
     */
    public static void zipDecompress(InputStream is, File destFile) {
        try (
                CheckedInputStream cis = new CheckedInputStream(is, new CRC32());
                ZipInputStream zis = new ZipInputStream(cis)
        ) {

            zipDecompress(zis, destFile);
            IOUtils.closeQuietly(cis);
            IOUtils.closeQuietly(zis);
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
    }

    /**
     * ʹ�� ZipInputStream ���н�ѹ����������ѹ����Ŀ���ļ���
     *
     * @param zis
     * @param destFile
     * @throws IOException
     */
    private static void zipDecompress(ZipInputStream zis, File destFile) throws IOException {
        while (true) {
            ZipEntry entry = zis.getNextEntry();
            if (entry == null) {
                break;
            }

            String dir = destFile.getPath() + File.separator + entry.getName();
            File dirFile = new File(dir);
            ensureFolderExists(dirFile);

            if (entry.isDirectory()) {
                dirFile.mkdir();
            } else {
                zipDecompressFile(zis, dirFile);
            }
            zis.closeEntry();
        }
    }

    /**
     * ��ѹ�����е�ǰ Entry �����ݽ�ѹ����ָ���ļ���
     * ������Ҫȷ����ǰ�� Entry ���ļ�����Ŀ¼��
     *
     * @param zis
     * @param destFile
     */
    public static void zipDecompressFile(ZipInputStream zis, File destFile) {
        try (
                FileOutputStream out = new FileOutputStream(destFile);
                BufferedOutputStream bos = new BufferedOutputStream(out)
        ) {
            IOUtils.copy(zis, bos);
            IOUtils.closeQuietly(out);
            IOUtils.closeQuietly(bos);
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
    }

    /**
     * ��ѹ���ļ���ѹ��Ϊ����ָ���ļ�����ļ�����ʹ���ļ���ԭʼ�ļ���
     * ���ַ�ʽѹ���ļ��б������ֻ�ܰ� 1 ���ļ���
     *
     * @param sourceFileName
     * @param destFileName
     * @throws IOException
     */
    public static void zipDecompressAsSingleFile(String sourceFileName, String destFileName) {
        try (
                CheckedInputStream cis = new CheckedInputStream(new FileInputStream(new File(sourceFileName)), new CRC32());
                ZipInputStream zis = new ZipInputStream(cis);
        ) {

            zis.getNextEntry();
            zipDecompressFile(zis, new File(destFileName));

            IOUtils.closeQuietly(zis);
            IOUtils.closeQuietly(cis);
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
    }

    /**
     * 获取当前路径
     *
     * @return
     */
    public static String getCurrentDir() {
        return ZipHelper.class.getClassLoader().getResource(".").getPath();
    }

    /**
     * <p>
     * 文件转换为byte数组
     * </p>
     *
     * @param filePath 文件路径
     * @return
     * @throws IOException
     */
    public static byte[] fileToBytes(String filePath) {
        byte[] data = null;
        try (
                FileInputStream in = new FileInputStream(new File(filePath));
                ByteArrayOutputStream out = new ByteArrayOutputStream();
        ) {

            IOUtils.copy(in, out);
            data = out.toByteArray();

            IOUtils.closeQuietly(in);
            IOUtils.closeQuietly(out);

        } catch (Exception e) {
            logger.error(e.getMessage());
        }
        return data;
    }

    /**
     * <p>
     * 二进制数据写文件
     * </p>
     *
     * @param bytes    二进制数据
     * @param filePath 文件生成目录
     * @throws IOException
     */
    public static void bytesToFile(byte[] bytes, String filePath) {

        File destFile = new File(filePath);
        if (!destFile.getParentFile().exists()) {
            destFile.getParentFile().mkdirs();
        }

        try (
                InputStream in = new ByteArrayInputStream(bytes);
                OutputStream out = new FileOutputStream(destFile);
        ) {
            IOUtils.copy(in, out);

            IOUtils.closeQuietly(in);
            IOUtils.closeQuietly(out);

        } catch (IOException e) {
            logger.error(e.getMessage());
        }
    }

    /**
     * 确保文件夹存在。不存在则创建
     *
     * @param folder
     */
    public static void ensureFolderExists(File folder) {
        File parentFile = folder.getParentFile();
        //递归查找上级目录，没有则创建
        if (!parentFile.exists()) {
            ensureFolderExists(parentFile);
            parentFile.mkdir();
        }
    }


    /**
     * 删除目录
     *
     * @param dir
     * @return
     */
    public static boolean deleteDir(File dir) throws IOException {
        if (dir.isDirectory()) {
            String[] children = dir.list();
            for (String s : children) {
                boolean success = deleteDir(new File(dir, s));
                if (!success) {
                    return false;
                }
            }
        }
        // 目录此时为空，可以删除
        Files.delete(dir.toPath());
        return true;
    }

}











